function transport(){
	var Self = this;
	/**
	 * @type playlist
	 */
	var Queue;
	var Pause = false;
	var Run = false;
	var IsCrossFading = false;
	var CrossFadeIntvl = 20;
	
	
/*  	  
	 CurrItem		 NextItem 
	    |				 |
	 CurrGain        NextGain
			\		 /
	     DynamicsCompressor (weiss nich ob ich den hier gut finde aber da er die audio daten verändert is vor analyser wohl sinnvoll)
			|		     \
	ChannelSplitter   	 Analyser (da solten dann mehrere connected werden, im draft steht das man mehr connecten kann aber dann braucht man auch nen ID damit wir auch wieder den richtigen disconnecten können... des weiß ich noch nich wie es funtzt)
	  /        \
 leftGain	 rightGain	   
	  \        /
	channelMerger
		  |
	  MasterGain
		  |
	   Context
*/
	
	
	var Context = new webkitAudioContext();
	var MasterGain = Context.createGainNode();
	var Analyser = Context.createAnalyser();
	
	this.init = function(){
		//setup audio route
		Analyser.connect(Context.destination);
		MasterGain.connect(Analyser);
		MasterGain.gain.value = 0.7;
		CORE.Input.attach("onGainChanged", onGainChanged);
		CORE.Input.attach("onProgressChanged", onProgressChanged);
		CORE.Input.attach("buttonPlay", this.play);
		CORE.Input.attach("buttonPause", this.pause);
		CORE.Input.attach("buttonStop", this.stop);
		CORE.Input.attach("buttonNext", this.next);
		CORE.Input.attach("buttonPrevious", this.previous);
		CORE.Input.attach("playForced", this.playForced); //!!!!!
		
		
		this.setGain(MasterGain.gain.value);
		update();
	};
	var update = function(){
		window.webkitRequestAnimationFrame(update, null);
		if(!Queue)return;
		var CurrItem = Queue.getCurr();
		if(CurrItem){
			//notify position event
			if(Run){
				CORE.notify("onPositionChanged",{
					process: CurrItem.CurrentTime*CurrItem.Duration, 
					position: CurrItem.CurrentTime,
					duration: CurrItem.Duration
				});
				//render seekBar
				var offset = CurrItem.CurrentTime/CurrItem.Duration;
				offset = offset*$("#transport .progress").width();
				$("#transport .progress .runner", CORE.Element).css("left", offset);
				//crossfading
				if(!IsCrossFading && CurrItem.CurrentTime + CrossFadeIntvl >= CurrItem.Duration && Queue.hasNext()){
					crossfade();
				}
				if(CurrItem.CurrentTime >= CurrItem.Duration){
					//ende von current abfangen und dann Queue.next()
					CurrItem.noteOff(0);
					CurrItem.disconnect();
					if(IsCrossFading){
						Queue.next();
						IsCrossFading = false;
					}
					CORE.notify("onEndOfMediaItem", null);
				}
				
			}
			
			var offset = CurrItem.CurrentTime/CurrItem.Duration;
			offset = offset*$("#transport .progress").width();
			$("#transport .progress .runner", CORE.Element).css("left", offset);
	
		}
		//render gainBar
		var left = MasterGain.gain.value*$("#transport .gain", CORE.Element).width();
		$("#transport .gain div", CORE.Element).css("left", left);
		

	};
	/**
	 * @param queue musst implement playQueueIterator
	 */
	this.setQueue = function(queue){
		Queue = queue;
	};
	this.play = function(){
		if(Pause){
			Run = true;
			Pause = false;
//			Queue.getCurr().connect(Context, MasterGain);
			Queue.getCurr().noteOn();
			if(IsCrossFading)Queue.getNext().noteOn();
			CORE.notify("onPlay");
			PlayerStateChanged();
		}
		if(!Queue.getCurr())return;
		if(Run)return;
		Run = true;
		Pause = false;
		Queue.getCurr().connect(Context, MasterGain);
		Queue.getCurr().noteOn(0);
		CORE.notify("onPlay");
		PlayerStateChanged();
	};
	this.playForced = function(items){
		if(Run || Pause){
			items.curr.noteOff(0);
			items.curr.disconnect();
		}
		if(IsCrossFading){
			items.next.noteOff(0);
			items.next.disconnect();
		}
		Run = false;
		Pause = false;
		IsCrossFading = false;
		Self.play();
	};
	this.stop = function(){
		if(!Run && !Pause)return;
		Queue.getCurr().noteOff(0);
		Queue.getCurr().disconnect();
		if(IsCrossFading){
			Queue.getNext().noteOff(0);
			Queue.getNext().disconnect();
		}
		CORE.notify("onStop");
		Run = false;
		Pause = false;
		IsCrossFading = false;
		PlayerStateChanged();
	};
	this.pause = function(){
		if(Pause)return false;
		Pause = true;
		Queue.getCurr().noteOff();
		if(IsCrossFading)Queue.getNext().noteOff();
		PlayerStateChanged();
	};
	this.next = function(){
		if(!Queue.hasNext())return false;
		if(Run){
			Queue.getCurr().noteOff(0);
			Queue.getCurr().disconnect();
			if(IsCrossFading){
				Queue.getNext().noteOff(0);
				Queue.getNext().disconnect();
				IsCrossFading = false;
			}
		}
		Queue.next();
		Run = true;
		Pause = false;
		Queue.getCurr().connect(Context, MasterGain);
		Queue.getCurr().noteOn(0);
		CORE.notify("onNext");
		PlayerStateChanged();
	};
	this.previous = function(){
		if(!Queue.hasPrevious())return false;
		if(Run){
			Queue.getCurr().noteOff(0);
			Queue.getCurr().disconnect();
			if(IsCrossFading){
				Queue.getNext().noteOff(0);
				Queue.getNext().disconnect();
				IsCrossFading = false;
			}
		}
		Queue.previous();
		Run = true;
		Pause = false;
		Queue.getCurr().connect(Context, MasterGain);
		Queue.getCurr().noteOn(0);
		CORE.notify("onPrevious");
		PlayerStateChanged();
	};
	
	//Crossfade
	var crossfade = function(e){
		if(!IsCrossFading){
			//Sets an array of arbitrary parameter values starting at time for the given duration. 
	        //The number of values will be scaled to fit into the desired duration. 
	        //void setValueCurveAtTime(in Float32Array values, in float time, in float duration);
			//des array setzen weir dann in einstellungen

			
			// fade out
			Queue.getCurr().Gain.gain.linearRampToValueAtTime(1, Context.currentTime);
			Queue.getCurr().Gain.gain.linearRampToValueAtTime(0, Context.currentTime+CrossFadeIntvl);
			//fade in
			Queue.getNext().connect(Context, MasterGain);
			Queue.getNext().Gain.gain.linearRampToValueAtTime(0, Context.currentTime);
			Queue.getNext().Gain.gain.linearRampToValueAtTime(1, Context.currentTime+CrossFadeIntvl);
			Queue.getNext().noteOn(0);
			IsCrossFading = true; 
		}
	};
	
	var onProgressChanged = function(e){
		if(!Queue.getCurr())return false;
		var offset = (e.pageX - $("#transport .progress", CORE.Element).offset().left);
		var progress = offset/$("#transport .progress", CORE.Element).width();
		Self.setProgress(progress);
	};
	/**
	 * @param progress float 0-1
	 */
	this.setProgress = function(progress){//progress in percent
		if(progress < 0 && progress > 1)return false;
			var time = Queue.getCurr().Duration*progress;
			Queue.getCurr().noteOff();
			Queue.getCurr().noteOn(time);
			//if(IsCrossFading) ????
	};
	var onGainChanged = function(e){
		var offset = (e.pageX - $("#transport .gain", CORE.Element).offset().left);
		var gain = offset/$("#transport .gain", CORE.Element).width();
		return Self.setGain(gain);
	};
	this.setGain = function(gain){
		if(gain < 0 && gain > 1)return false;
		MasterGain.gain.value = gain;
	};
	
	
	this.isPaused = function(){
		return Pause;
	};
	this.isPlaying = function(){
		return Run;
	};
	this.getAnalyser = function(){
		return Analyser;
	};
	this.getGain = function(){
		return MasterGain.gain.value;
	};
	var PlayerStateChanged = function(){
		CORE.notify("onStateChanged", {
			activeItem: (Queue.getCurr())?true:false,
			paused: Self.isPaused(),
			playing: Self.isPlaying()
		});
	};
//	this.hasActiveItem = function(){
//		return CurrItem;
//	};



	this.init();
}